function IndustryChainGraph(el, options = {}) {
  const dom = $(el)
  if (!dom) {
    return
  }
  const config = {
    // 是否添加事件
    hasEvent: true,
    height: '1000px',
    width: '100%',
    data: {
      data: {
        entity: {
          graph: {
            vertexs: [],
            edges: []
          }
        }
      }
    }
  }
  Object.assign(config, options)
  dom.html(`<div ref="mynetworkRef" class="mynetwork" style="width: ${config.width};height: ${config.height}"></div>`)
  initGraph(el, config)
}

const colorConfig = {
    edge: {
      color: '#686258',
      hover: '#35363c',
      editColor: '#47979E'
    },
    node: {
      color: '#2A303D',
      font: {
        color: 'rgba(255, 255, 255, 0.6)'
      },
      highlightEdit: Color('#d3b782').alpha(0.4).string()
    },
    themeBgColor: '#121927'
  },
  storeVertexs = new StoreVertexs()
let visGraph = null

function initGraph(el, config) {
  new Vue({
    el,
    data: () => ({
      // 图节点
      vertexs: [],
      // 图边
      edges: [],
      // 图节点数据
      graphNodes: new vis.DataSet(),
      // 图边数据
      graphEdges: new vis.DataSet(),
      nodePolymer: {
        isShow: false,
        list: []
      },
      visOptions: {
        // 如果为true，Network可以自动检测容器的大小，并进行相应地重绘。
        autoResize: true,
        // 开启物理引擎
        physics: false,
        interaction: {
          selectConnectedEdges: false,
          //当为真时，拖动视图时不绘制边沿。这可以大大加快拖动的响应性，提高用户体验。
          hideEdgesOnDrag: false,
          tooltipDelay: 3600000 * 24,
          hover: true
        },
        // 节点配置
        nodes: {
          margin: 10,
          widthConstraint: {
            minimum: 50,
            maximum: 40
          },
          heightConstraint: {
            minimum: 50
          },
          shape: 'circle',
          borderWidthSelected: 1,
          color: {
            border: colorConfig.node.color,
            background: colorConfig.node.color,
            hover: {
              border: '#373E4F',
              background: '#373E4F'
            },
            highlight: {
              border: colorConfig.node.color,
              background: colorConfig.node.color
            }
          },
          font: {
            color: colorConfig.node.font.color,
            size: 16
          }
        },
        // 边配置
        edges: {
          width: 2,
          // length: 250,
          shadow: false,

          color: {
            color: colorConfig.edge.color,
            highlight: colorConfig.edge.color,
            hover: colorConfig.edge.hover
          },
          font: {
            align: 'middle',
            strokeWidth: 0,
            color: 'transparent'
          },
          hoverWidth: () => 1,
          arrows: {
            to: {
              enabled: true,
              scaleFactor: 0.5
            }
          },
          smooth: {
            type: 'curvedCW',
            roundness: 0
          },
          arrowStrikethrough: false
        },
        layout: {
          randomSeed: 500
        }
      },
      // 编辑节点
      nodeEdit: {
        // 是否添加节点模式
        isAddNodeMode: false,
        // 是否编辑节点模式（单击节点添加时）
        isEditNodeMode: false,
        // 是否更新节点节点模式（双击节点时）
        isUpdateNodeMode: false,
        nodeId: '',
        edgeFromId: '',
        edgeToId: '',
        input: '',
        styles: {
          circle: {},
          container: {}
        }
      },
      // 图缩放限制
      graphScale: {
        min: 0.4
      },
      // 节点圆度
      nodeRadius: 45,
      // 是否编辑模式
      isEditMode: false,
      // 节点操作，包含显示添加，删除控制
      nodeOpera: {
        opera: 'add',
        isShow: false,
        nodeId: '',
        label: '',
        styles: {
          circle: {},
          text: {},
          container: {}
        }
      },
      // 拖拽控制
      drag: {
        nodeId: ''
      },
    }),
    computed: {
      // 根据图默认配置设计节点大小，便于设置 dom 元素
      nodeSize() {
        return this.visOptions.nodes.widthConstraint.minimum + this.visOptions.nodes.margin * 2
      },
    },
    mounted() {
      // Utils.http('http://172.25.65.35:8022/mock/17/sam/chainIndustry/v2/queryMasterGraph', {
      //   'chainCode': 'CHAIN_DOME_PV_001'
      // }).then(res => {
      this.vertexs = config.data.data.entity.graph.vertexs
      this.edges = config.data.data.entity.graph.edges

      // 生成聚合数据
      this.generatePolymerData(this.vertexs)

      this.$nextTick(() => {
        this.drawGraph(this.vertexs, this.edges)
        $('.mynetwork > .vis-network').css({outline: 'none'})
      })
      // })
    },
    methods: {
      // 转换需要的复合节点数据结构
      generatePolymerData(vertexsData) {
        this.nodePolymer.list = vertexsData.map((item) => {
          if (item.polymerFlag) {
            return {
              id: item.id,
              scale: 1,
              x: item.x,
              y: item.y,
              isGray: false,
              hidden: false
            }
          }
        }).filter(x => x)
      },
      // 绘制图
      drawGraph(nodes, edges) {
        this.addEdge(edges)
        this.addNode(nodes)
        if (!this.$refs.mynetworkRef) {
          return
        }
        // 存储所有绘制节点，仅适用于中信POC
        if (isPoc(this.code)) {
          const nodeList = []
          this.graphNodes.forEach(node => {
            nodeList.push(node)
          })
          storeVertexs.set(nodeList)
        }

        if (!config.hasEvent) {
          this.visOptions.interaction = {
            tooltipDelay: 3600000 * 24,
            selectConnectedEdges: false,
            // selectable: false,
            dragNodes: false,
            dragView: false,
            zoomView: false,
            hover: true
          }
        }

        visGraph = new vis.Network(this.$refs.mynetworkRef, {
          nodes: this.graphNodes,
          edges: this.graphEdges
        }, this.visOptions)

        this.resetVisPosition()

        visGraph.doubleClickTime = 0
        visGraph.doubleClickThreshold = 200

        this.renderPolymer()
        this.addEvent()
      },
      addEvent() {
        visGraph.on('doubleClick', (t) => {
        })

        visGraph.on('click', (t) => {
        })

        visGraph.on('hoverNode', (t) => {
          const nodeId = t.node
          let connectedEdges = visGraph.getConnectedEdges(nodeId)

          // 连接节点的边动画
          if (connectedEdges.length) {
            connectedEdges = connectedEdges.map((edgeId) => {
              const nodeRadius = this.visOptions.nodes.widthConstraint.maximum / 2 + this.visOptions.nodes.margin
              return {
                edge: edgeId,
                trafficSize: 3,
                nodeSize: nodeRadius
              }
            })

            visGraph.animateTraffic(connectedEdges)
          }

          visGraph.unselectAll()
        })

        visGraph.on('blurNode', (t) => {
          visGraph.animateTrafficClear()
        })

        visGraph.on('hoverEdge', (t) => {
          // 获取兄弟边
          const siblingEdges = this.getSiblingEdge(t.edge)
          // 控制兄弟边动画效果
          const connectedEdges = siblingEdges.map((item) => {
            const nodeRadius = this.visOptions.nodes.widthConstraint.maximum / 2 + this.visOptions.nodes.margin
            return {
              edge: item.id,
              trafficSize: 3,
              nodeSize: nodeRadius
            }
          })

          visGraph.animateTraffic(connectedEdges)
          visGraph.unselectAll()
        })

        visGraph.on('blurEdge', (t) => {
          const edgeId = t.edge
          const curEdgeData = this.graphEdges.get(edgeId)
          if (!curEdgeData) {
            return
          }

          const edgeColor = _.cloneDeep(curEdgeData.originColor)

          this.graphEdges.update({
            id: edgeId,
            color: edgeColor,
            dashes: false
          })
          visGraph.animateTrafficClear()
        })

        visGraph.on('oncontext', (t) => t.event.preventDefault())

        visGraph.on('resize', (t) => {
          visGraph.animateTrafficClear()

          setTimeout(() => {
            this.renderPolymer()
          }, 0)
        })

        visGraph.on('zoom', (t) => {
          if (t.scale <= this.graphScale.min) {
            visGraph.moveTo({
              scale: this.graphScale.min,
              position: {x: 0, y: 0}
            })
          }
          visGraph.animateTrafficClear()
          this.renderPolymer()
        })

        visGraph.on('dragStart', (t) => {
          if (t.nodes.length) {
            const [nodeId] = t.nodes

            this.drag.nodeId = nodeId
            this.updatePolymer(this.drag.nodeId)
          } else {
            this.renderPolymer()
          }
        })

        visGraph.on('dragging', (t) => {
          this.dragControlNode(t)
          visGraph.animateTrafficClear()
          this.nodeOpera.isShow = false

          if (this.drag.nodeId) {
            this.updatePolymer(this.drag.nodeId)
          } else {
            this.renderPolymer()
          }
        })

        visGraph.on('dragEnd', (t) => {
          this.dragControlNode(t)
          visGraph.animateTrafficClear()

          if (this.drag.nodeId) {
            this.updatePolymer(this.drag.nodeId)
            this.drag.nodeId = ''
          } else {
            this.renderPolymer()
          }
        })

        // 添加边模式拖拽
        visGraph.on('controlNodeDragging', (t) => {
          const {from, to} = t.controlEdge
          const fromNodeData = this.graphNodes.get(from)
          const connectedNodes = visGraph.getConnectedNodes(from)
          const {fromToIds, toFromIds} = this.getEdgeId(from, to)

          connectedNodes.forEach((nodeId) => {
            const curNodeData = this.graphNodes.get(nodeId)
            if (curNodeData) {
              this.graphNodes.update({
                id: nodeId,
                ...this.getNodeGrayColor(curNodeData)
              })
            }
          })

          const {groupFlag, groupCode} = fromNodeData.data
          // 当前节点是组节点，不可以连接组内子节点
          if (groupFlag) {
            this.graphNodes.forEach((item) => {
              if (item.data.groupCode === from) {
                this.graphNodes.update({
                  id: item.id,
                  ...this.getNodeGrayColor(item)
                })

                if (to && from !== to) {
                  const {groupCode: groupCodeTo} = this.graphNodes.get(to).data
                  if (groupCodeTo === from) {
                    jsBridge.callBridge('toast', {msg: '当前节点不可以与子节点进行连接'})
                  }
                }
              }
            })
          }

          // 当前节点是组内子节点，不可以与组节点相连
          if (groupCode) {
            this.graphNodes.update({
              id: groupCode,
              ...this.getNodeGrayColor(fromNodeData)
            })

            if (to && from !== to) {
              const {id: toId} = this.graphNodes.get(to).data
              if (groupCode && groupCode === toId) {
                jsBridge.callBridge('toast', {msg: '当前节点不可以与组节点进行连接'})
              }
            }
          }

          // 组内节点不能相互连接
          if (groupCode) {
            this.graphNodes.forEach((item) => {
              if (groupCode === item.data.groupCode && item.id !== from) {
                this.graphNodes.update({
                  id: item.id,
                  ...this.getNodeGrayColor(item)
                })
              }
            })

            if (to && from !== to) {
              const {groupCode: groupCodeFrom} = this.graphNodes.get(from).data
              const {groupCode: groupCodeTo} = this.graphNodes.get(to).data
              if (groupCodeFrom === groupCodeTo) {
                jsBridge.callBridge('toast', {msg: '组内节点不可以进行相互连接'})
              }
            }
          }

          // 已经连接的节点 不可以添加添加边提示，单实例控制
          if (to && from !== to && (fromToIds.length || toFromIds.length)) {
            jsBridge.callBridge('toast', {msg: '不可重复创建边或添加双向边'})
          }

          visGraph.animateTrafficClear()
        })

        visGraph.on('controlNodeDragEnd', (t) => {
          const {from, to} = t.controlEdge
          const {fromToIds, toFromIds} = this.getEdgeId(from, to)

          // 链接当前节点
          if (from === to) {
            this.graphEdges.remove(fromToIds[0])
          }

          // 重复添加同向链接
          if (fromToIds.length > 1) {
            this.graphEdges.remove(fromToIds[1])
          }

          // 添加反向链接
          if (fromToIds.length && toFromIds.length) {
            this.graphEdges.remove(fromToIds[0])
          }

          // 组与组内节点相连
          if (fromToIds.length) {
            const connectNodeFrom = this.graphEdges.get(fromToIds[0])
            if (connectNodeFrom) {
              const {from, to} = connectNodeFrom
              const {groupFlag: groupFlagFrom, groupCode: groupCodeFrom} = this.graphNodes.get(from).data
              const {groupFlag: groupFlagTo, groupCode: groupCodeTo} = this.graphNodes.get(to).data
              if (groupFlagFrom && from === groupCodeTo ||
                groupFlagTo && to === groupCodeFrom
              ) {
                this.graphEdges.remove(fromToIds[0])
              }
            }
          }

          // 组内节点相连
          if (fromToIds.length) {
            const connectNodeFrom = this.graphEdges.get(fromToIds[0])
            if (connectNodeFrom) {
              const {from, to} = connectNodeFrom

              if (from && to) {
                const {groupCode: groupCodeFrom} = this.graphNodes.get(from).data
                const {groupCode: groupCodeTo} = this.graphNodes.get(to).data
                if (groupCodeFrom && groupCodeTo && groupCodeFrom === groupCodeTo) {
                  this.graphEdges.remove(fromToIds[0])
                }
              }
            }
          }

          this.resetAllEdgeNode()

          // 删除无from，无to的无效边
          const clearInvalidEdge = () => {
            this.graphEdges.forEach((item) => {
              if (!item.from || !item.to) {
                this.graphEdges.remove(item.id)
              }
            })
          }

          if (fromToIds.length === 1 && !toFromIds.length) {
            this.graphEdges.update({
              id: fromToIds[0],
              originColor: _.cloneDeep(this.visOptions.edges.color),
              color: _.cloneDeep(this.visOptions.edges.color)
            })
            this.isChange = true
            this.isAddEdgeMode = false
            visGraph.disableEditMode()
            clearInvalidEdge()
          } else {
            clearInvalidEdge()
            visGraph.addEdgeMode()
          }
        })
      },
      // 图基本添加节点方法
      addNode(t) {
        const newNodes = []
        let nodes = t
        if (!Array.isArray(nodes)) {
          nodes = [t]
        }
        nodes = _.uniqBy(nodes, 'id')
        nodes.forEach((item) => {
          let color = item.vertexColor || colorConfig.node.color
          if (item.groupFlag) {
            color = Color(color).darken(0.5).hex()
          }

          const curNodeColorConfig = {
            border: color,
            background: color,
            hover: {
              border: Color(color).lighten(0.3).hex(),
              background: Color(color).lighten(0.3).hex()
            },
            highlight: {
              border: color,
              background: color
            }
          }

          const curNodeFontConfig = {
            ..._.cloneDeep(this.visOptions.nodes.font),
            size: item.properties.name.length >= 7 ? 12 : 16
          }

          // 图节点的基本数据
          const data = {
            label: item.properties.name,
            title: '',
            propertiesLabel: item.label,
            type: 'node',
            data: item,
            originColor: _.cloneDeep(curNodeColorConfig),
            color: _.cloneDeep(curNodeColorConfig),
            font: _.cloneDeep(curNodeFontConfig),
            originFont: _.cloneDeep(curNodeFontConfig)
          }
          // 根据组表示设置节点图形
          if (item.groupFlag) {
            data.shape = 'box'
            data.shapeProperties = {
              borderRadius: 16
            }
          }
          if (item.id) {
            data.id = item.id
          }
          if (item.x) {
            data.x = item.x
          }
          if (item.y) {
            data.y = item.y
          }

          newNodes.push(...this.graphNodes.update([data]))
        })

        return newNodes
      },
      // 图基本添加边方法
      addEdge(t) {
        const newEdges = []
        let edges = t
        if (!Array.isArray(edges)) {
          edges = [t]
        }

        edges.forEach((item) => {
          // 边基本数据结构
          const data = {
            from: item.outV,
            to: item.inV,
            label: item.label,
            title: '',
            type: 'edge',
            data: item,
            originColor: _.cloneDeep(this.visOptions.edges.color),
            color: _.cloneDeep(this.visOptions.edges.color)
          }
          if (item.id) {
            data.id = item.id
          }

          newEdges.push(...this.graphEdges.update([data]))
        })

        return newEdges
      },
      // 重置图位置，缩放
      resetVisPosition() {
        visGraph.moveTo({
          scale: 0.4,
          position: {x: 0, y: 0}
        })
        this.renderPolymer()
      },
      updatePolymer(nodeId) {
        if (!nodeId) {
          return
        }
        const scale = visGraph.getScale()
        const {x, y} = visGraph.getPositions([nodeId])[nodeId]
        const corner = visGraph.canvasToDOM({x, y})

        this.nodePolymer.isShow = true
        this.nodePolymer.list = this.nodePolymer.list.map((item) => {
          if (nodeId === item.id) {
            item.x = corner.x + ((this.nodeSize * scale) / 2) * Math.cos(2 * Math.PI / 360 * 45)
            item.y = corner.y + ((this.nodeSize * scale) / 2) * Math.sin(2 * Math.PI / 360 * 45)
            item.scale = scale
            item.isGray = true
          }
          return item
        })
      },
      // 批量更新复合节点DOM
      renderPolymer() {
        this.$refs.mynetworkRef && this.graphNodes.forEach((node) => {
          this.updatePolymer(node.id, node.x, node.y)
        })
      },
      // 获取事件下的nodeId, edgeId
      getEventAt(t) {
        const n = (t.event, t.pointer.DOM)
        const node = visGraph.getNodeAt(n)
        const edge = visGraph.getEdgeAt(n)
        return {
          node,
          edge
        }
      },
      // 拖拽控制DOM节点
      dragControlNode(t) {
        const {node} = this.getEventAt(t)
        // 添加节点模式可以拖拽新节点
        if (node && node === this.nodeEdit.nodeId && this.nodeEdit.isAddNodeMode) {
          const {x, y} = visGraph.getPositions([node])[node]
          const corner = visGraph.canvasToDOM({x, y})
          const container = visGraph.body.container
          const containerW = container.offsetWidth
          const containerH = container.offsetHeight
          const limitPos = _.cloneDeep(corner)
          const scale = visGraph.getScale()
          const nodeSize = this.nodeRadius * scale

          if (corner.x < nodeSize) {
            limitPos.x = nodeSize
          }
          if (corner.x + nodeSize > containerW) {
            limitPos.x = containerW - nodeSize
          }
          if (corner.y < nodeSize) {
            limitPos.y = nodeSize
          }
          if (corner.y + nodeSize > containerH) {
            limitPos.y = containerH - nodeSize
          }
          const nodePos = visGraph.DOMtoCanvas(limitPos)
          if (corner.x < nodeSize || corner.y < nodeSize ||
            corner.x + nodeSize > containerW || corner.y + nodeSize > containerH) {
            dragNodeTimer && clearTimeout(dragNodeTimer)
            const dragNodeTimer = setTimeout(() => {
              visGraph.moveNode(this.nodeEdit.nodeId, nodePos.x, nodePos.y)
            }, 10)
          }

          this.nodeEdit.styles.container.left = `${limitPos.x}px`
          this.nodeEdit.styles.container.top = `${limitPos.y}px`
        }
      },
      // 根据出度，入度获取边
      getEdgeId(from, to) {
        const fromToIds = []
        const toFromIds = []
        this.graphEdges.forEach((edge) => {
          if (edge.from === from && edge.to === to) {
            fromToIds.push(edge.id)
          }
          if (edge.from === to && edge.to === from) {
            toFromIds.push(edge.id)
          }
        })
        return {
          fromToIds,
          toFromIds
        }
      },
      // 获取置灰节点颜色
      getNodeGrayColor(node) {
        // 获取与底色的渐变色，若使用透明度方式会露出节点出度的边
        const bgColor = visGraph.gradient(node.originColor.background, colorConfig.themeBgColor, 10)[8]
        const fontColor = Color(node.originFont.color).alpha('0.2').string()
        const borderColor = Color(node.originColor.border).alpha('0.2').string()
        return {
          color: {
            background: bgColor,
            border: borderColor,
            hover: {
              background: bgColor,
              border: borderColor
            },
            highlight: {
              background: bgColor,
              border: borderColor
            }
          },
          font: {
            color: fontColor
          }
        }
      },
      // 重置所有节点，边
      resetAllEdgeNode() {
        // 恢复所有 edge
        this.graphEdges.forEach((edge) => {
          edge.color = _.cloneDeep(edge.originColor)
          this.graphEdges.update(edge)
        })

        // 恢复所有 node
        this.graphNodes.forEach((node) => {
          this.graphNodes.update({
            id: node.id,
            fixed: false,
            color: _.cloneDeep(node.originColor),
            font: _.cloneDeep(node.originFont)
          })
        })
        this.nodeEdit.edgeFromId = ''
        this.nodeEdit.edgeToId = ''
      },
      // 根据边相关属性获取通属性下兄弟边
      getSiblingEdge(edgeId) {
        const curEdgeData = this.graphEdges.get(edgeId)
        return this.graphEdges.map((item) => {
          if (curEdgeData.label === item.label && item.from === curEdgeData.from) {
            return item
          }
        }).filter((item) => {
          return item
        })
      }
    }
  })
}

function isPoc(code) {
  // 目前POC的产业链仅有智能手机产业链
  return code === 'CHAIN_CTIC_Smartphone'
}

/**
 * storeVertexs: 存储产业链主图的所有节点
 * */
function StoreVertexs() {
  this.nodes = []
}

StoreVertexs.prototype.set = function (value) {
  this.nodes = value
}
StoreVertexs.prototype.get = function () {
  return this.nodes
}